#pragma once
#include<iostream>
#include<queue>
#include<pthread.h>
#include<unistd.h>
namespace Block_queue{
    template<class T>
    class block_queue{
        public:
            block_queue(int size = 10):_max_size(size),_c_wait_num(0),_p_wait_num(0)
            {
                pthread_mutex_init(&_mutex,nullptr);//互斥锁初始化
                pthread_cond_init(&_consumer_cond,nullptr);//消费者条件变量初始化
                pthread_cond_init(&_producer_cond,nullptr);//生产者条件变量初始化
            }
            void push(const T& data)//Producer
            {
                
                pthread_mutex_lock(&_mutex);//加锁
                while(_queue.size() == _max_size){//判断必然是在临界区内的，因为判断也访问了临界资源，所以等待时是持有锁的
                    _p_wait_num++;//生产者等待数加1
                    pthread_cond_wait(&_producer_cond,&_mutex);//等待生产者条件变量通知(此时会释放锁)
                    //线程被唤醒后需要重新申请并持有锁（会在临界区中醒来）
                    _p_wait_num--;//生产者等待数减1
                }
                _queue.push(data);
                if(_c_wait_num > 0){//有消费者等待则通知
                    pthread_cond_signal(&_consumer_cond);//通知消费者条件变量
                }
                pthread_mutex_unlock(&_mutex);//解锁
            }
            void pop(T* out)//Consumer
            {
                pthread_mutex_lock(&_mutex);//加锁
                while(_queue.empty()){//防止伪唤醒
                    //判断必然是在临界区内的，因为判断也访问了临界资源，所以等待时是持有锁的
                    _c_wait_num++;//消费者等待数加1
                    pthread_cond_wait(&_consumer_cond,&_mutex);//等待消费者条件变量通知(此时会释放锁)
                    //线程被唤醒后需要重新申请并持有锁（会在临界区中醒来）
                    _c_wait_num--;//消费者等待数减1
                }
                *out = _queue.front();
                _queue.pop();
                if(_p_wait_num > 0){//有生产者等待则通知
                    pthread_cond_signal(&_producer_cond);//通知生产者条件变量
                }
                pthread_mutex_unlock(&_mutex);//解锁
            }
            ~block_queue()
            {
                pthread_mutex_destroy(&_mutex);//互斥锁销毁
                pthread_cond_destroy(&_consumer_cond);//消费者条件变量销毁
                pthread_cond_destroy(&_producer_cond);//生产者条件变量销毁
            }
        private:
            std::queue<T> _queue;
            pthread_mutex_t _mutex;//互斥锁
            pthread_cond_t _consumer_cond;//消费者条件变量
            pthread_cond_t _producer_cond;//生产者条件变量
            int _max_size;//队列最大容量
            int _c_wait_num;
            int _p_wait_num;
    };
}